package com.botarena.client.bot;

import com.botarena.client.SiteTokens;
import com.botarena.client.bot.remote.BotAccess;
import com.botarena.client.bot.remote.BotAccessAsync;
import com.botarena.client.ui.ErrorDialogBox;
import com.botarena.client.ui.InformationDialogBox;
import com.botarena.client.ui.SourceViewDialogBox;
import com.botarena.client.ui.StringHelper;
import com.botarena.shared.BotInfo;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.Window.Location;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;

/**
 * GWT widget for representing single bot form on My Bots page.
 */
public class BotEditFormWidget {
	
	private static final String SHOW_SOURCE_BUTTON_LABEL = "Show source";
	private static final String SHOW_FIGHTS_BUTTON_LABEL = "Show fights";
	private static final String SHOW_HOMEPAGE_BUTTON_LABEL = "Homepage";
	private static final String DELETE_BUTTON_LABEL = "Delete";
	private static final String UPDATE_BUTTON_LABEL = "Update";
	
	private static final String SHOW_BUTTONS_WIDTH = "100px";
	private static final String MAIN_BUTTONS_WIDTH = "70px";
	
	private BotInfo botInfo;

	private TextBox name;
	private TextBox parameters;
	private CheckBox state;
	
	private Button showSource;
	private Button showFights;
	private Button showHomepage;
	private Button deleteButton;
	private Button updateButton;

	private HorizontalPanel panel;
	private BotEditor botEditor;

	public BotEditFormWidget(BotEditor botEditor, BotInfo botInfo) {
		this.botInfo = botInfo;
		this.botEditor = botEditor;
		
		initWidgetElements();
		refresh();
	}

	private void refresh() {
		panel.clear();
		createInfoForm();
		createEditForm();
	}
	
	public HorizontalPanel getPanel() {
		return panel;
	}

	private void initWidgetElements() {
		panel = new HorizontalPanel();
		panel.addStyleName("formTable");
		
		name = new TextBox();
		parameters = new TextBox();
		state = new CheckBox("contestant");
		
		initShowSourceButton();
		initShowFightsButton();
		initShowHomepageButton();
		initDeleteButton();
		initUpdateButton();
	}

	private void createInfoForm() {
		Grid infoGrid = new Grid(5, 2);
		
		infoGrid.setText(0, 0, "Name:");
		infoGrid.setText(1, 0, "Ranking:");
		infoGrid.setText(2, 0, "Wins:");
		infoGrid.setText(3, 0, "Losses:");
		infoGrid.setText(4, 0, "Draws");
		
		infoGrid.setText(0, 1, StringHelper.limitedLengthString(botInfo.getName(), 15));
		infoGrid.setText(1, 1, Integer.toString(botInfo.getPoints()));
		infoGrid.setText(2, 1, Integer.toString(botInfo.getWins()));
		infoGrid.setText(3, 1, Integer.toString(botInfo.getLosses()));
		infoGrid.setText(4, 1, Integer.toString(botInfo.getDraws()));
		
		VerticalPanel infoPanel = new VerticalPanel();
		infoPanel.add(infoGrid);
		infoPanel.add(showSource);
		infoPanel.add(showFights);
		infoPanel.add(showHomepage);
		
		panel.add(infoPanel);
		panel.setCellHorizontalAlignment(infoPanel, HorizontalPanel.ALIGN_LEFT);
	}
	
	private void createEditForm() {
		Grid editGrid = new Grid(4, 2);
		
		editGrid.setText(0, 0, "Name:");
		editGrid.setText(1, 0, "Parameters:");
		editGrid.setText(2, 0, "State:");
		editGrid.setWidget(3, 0, deleteButton);
		
		name.setText(botInfo.getName());
		editGrid.setWidget(0, 1, name);
		parameters.setText(botInfo.getParameters());
		editGrid.setWidget(1, 1, parameters);
		state.setValue(botInfo.isContestant());
		editGrid.setWidget(2, 1, state);
		editGrid.setWidget(3, 1, updateButton);
		
		editGrid.getCellFormatter().setHorizontalAlignment(3, 0, HasHorizontalAlignment.ALIGN_LEFT);
		editGrid.getCellFormatter().setHorizontalAlignment(3, 1, HasHorizontalAlignment.ALIGN_RIGHT);
		
		panel.add(editGrid);
		panel.setCellHorizontalAlignment(editGrid, HorizontalPanel.ALIGN_RIGHT);
	}

	private void initUpdateButton() {
		updateButton = new Button(UPDATE_BUTTON_LABEL, new ClickHandler() {
			
			@Override
			public void onClick(ClickEvent event) {
				final BotInfo updatedBotInfo = getFormValues();
				BotAccessAsync botService = GWT.create(BotAccess.class);
				botService.updateBot(updatedBotInfo, new AsyncCallback<BotInfo>() {
					
					@Override
					public void onSuccess(BotInfo result) {
						if (result == null) {
							refresh();
							showErrorDialogBox("Error", "A bot with name " + updatedBotInfo.getName() + " already exists, please try other name.");
						} else {
							botInfo = result;
							botEditor.updateBot(result);
							refresh();
							showInformationDialogBox("Success", "Bot successfully updated");
						}
					}
					
					@Override
					public void onFailure(Throwable caught) {
						refresh();
						showErrorDialogBox("Error", "Sorry, unable to update bot.");
					}
				});
			}
		});
		updateButton.setWidth(MAIN_BUTTONS_WIDTH);
	}
	
	private BotInfo getFormValues() {
		BotInfo botInfo = new BotInfo();
		botInfo.setKey(this.botInfo.getKey());
		botInfo.setName(name.getText());
		botInfo.setParameters(parameters.getText());
		botInfo.setContestant(state.getValue());
		return botInfo;
	}

	private void initDeleteButton() {
		deleteButton = new Button(DELETE_BUTTON_LABEL, new ClickHandler() {
			
			@Override
			public void onClick(ClickEvent event) {
				BotAccessAsync botService = GWT.create(BotAccess.class);
				botService.deleteBot(botInfo.getKey(), new AsyncCallback<Void>() {
					
					@Override
					public void onSuccess(Void result) {
						panel.clear();
						InformationDialogBox dialogBox = new InformationDialogBox("Delete");
						dialogBox.setMessage("Bot has been deleted!");
						dialogBox.center();
						botEditor.deleteBot(botInfo);
					}
					
					@Override
					public void onFailure(Throwable caught) {
						panel.clear();
						panel.add(new Label("Sorry, unable to delete the bot.."));
					}
				});
			}
		});
		deleteButton.setWidth(MAIN_BUTTONS_WIDTH);
	}
	
	private void initShowSourceButton() {
		showSource = new Button(SHOW_SOURCE_BUTTON_LABEL, new ClickHandler() {
			
			@Override
			public void onClick(ClickEvent event) {
				showSourceDialogBox(botInfo.getName(), botInfo.getSourceCode());
			}
		});
		showSource.setWidth(SHOW_BUTTONS_WIDTH);
	}

	private void initShowFightsButton() {
		showFights = new Button(SHOW_FIGHTS_BUTTON_LABEL, new ClickHandler() {
			
			@Override
			public void onClick(ClickEvent event) {
				StringBuffer buf = new StringBuffer("http://");
                buf.append(Location.getHost()).append("#").append(
                                SiteTokens.BATTLES).append('?')
                                .append(botInfo.getKey());
                Location.replace(buf.toString());
			}
		});
		showFights.setWidth(SHOW_BUTTONS_WIDTH);
	}
	
	private void initShowHomepageButton() {
		showHomepage = new Button(SHOW_HOMEPAGE_BUTTON_LABEL, new ClickHandler() {
			
			@Override
			public void onClick(ClickEvent event) {
				StringBuffer buf = new StringBuffer("http://");
				buf.append(Location.getHost()).append("#").append(
						SiteTokens.BOT_HOME).append('?').append(
						botInfo.getKey());
				Location.replace(buf.toString());
			}
		});
		showHomepage.setWidth(SHOW_BUTTONS_WIDTH);
	}

	private void showInformationDialogBox(String title, String message) {
		InformationDialogBox dialogBox = new InformationDialogBox(title);
		dialogBox.setMessage(message);
		dialogBox.center();
	}
	
	private void showErrorDialogBox(String title, String message) {
		ErrorDialogBox dialogBox = new ErrorDialogBox(title);
		dialogBox.setMessage(message);
		dialogBox.center();
	}
	
	private void showSourceDialogBox(String name, String source) {
		SourceViewDialogBox dialog = new SourceViewDialogBox(name, source);
		dialog.center();
	}
}
